package com.rpc.thriftrpcserver;

import com.rpc.rpcserverdef.RpcServer;
import com.rpc.rpcserverdef.RpcServerException;
import java.lang.reflect.Method;
import java.util.Properties;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;
import org.kohsuke.MetaInfServices;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@MetaInfServices(RpcServer.class)
public class ThriftServer implements RpcServer {
    private final static Logger log = LoggerFactory.getLogger(ThriftServer.class);
    
    private TServer server;
    
    public void start(Properties appConfig) throws RpcServerException {
        try {
            log.info("Starting configuration of a Thrift server instance");
            
            final String serviceHandlerClassName =  (String)appConfig.get("ServiceHandlerClass");
            
            if (log.isDebugEnabled()) {
                log.debug("Loading Thrift service handler class: " + serviceHandlerClassName);
            }
            
            Class serviceHandlerClass = Class.forName(serviceHandlerClassName);
            
            if (log.isDebugEnabled()) {
                log.debug("Creating instance of " + serviceHandlerClass.getName());
            }
            
            Object handler = serviceHandlerClass.newInstance();
       
            
            if (log.isDebugEnabled()) {
                log.debug("Loading Thrift service class: " + serviceHandlerClassName);
            }
            
            Class thriftServiceClass = Class.forName((String) appConfig.get("ThriftServiceClass"));
       
            Class[] params = new Class[1];
            params[0] = serviceHandlerClass;
            
            if (log.isDebugEnabled()) {
                log.debug("Finding 'Processor' methd on " + thriftServiceClass.getName());
            }
            
            Method m = thriftServiceClass.getDeclaredMethod("Processor", params );
           
            if (log.isDebugEnabled()) {
                log.debug("Invoking Processor method on " + thriftServiceClass.getName() + " with argument of type:" + serviceHandlerClass.getName());
            }
            
            Object processor =  m.invoke(null, new Object[] {handler});
           
            int appSocketNumber = Integer.parseInt((String) appConfig.get("AppSocketNumber"));
            
            if (log.isDebugEnabled()) {
                log.debug("Creating instance of TServerTransport configured for port: " + appSocketNumber);
            }
            
            TServerTransport serverTransport = new TServerSocket(appSocketNumber);
           
            TThreadPoolServer.Args tserverArgs = new TThreadPoolServer.Args(serverTransport);
            
            this.server = new TThreadPoolServer(tserverArgs);
            
            if (log.isDebugEnabled()) {
                log.debug("Starting Thrift server");
            }
            
            server.serve();
            
            if (log.isDebugEnabled()) {
                log.debug("Thrift server started");
            }
            
            log.info("Finished configuration of a Thrift server instance");
           
        } catch (Exception ex) {
            log.error("Unable to start Thrift server instance", ex);
            throw new RpcServerException("Unable to start server", ex);
        }
    }

    public void stop() throws RpcServerException {
        try {
            if (server != null) {
                log.debug("Stopping thrift server instance");
                server.stop();
                log.debug("Stopped thrift server instance");
            }
        }catch (Exception ex) {
            log.error("Unable to stop thrift server instance.", ex);
            throw new RpcServerException("Unable to stop thrift server instance.", ex);
        }
        
    }

    public String getName() {
        return "THRIFT";
    }
    
}
